﻿using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace Microsoft.Extensions.Logging.File
{
    [ProviderAlias("File")]
    public class FileLoggerProvider : ILoggerProvider, IDisposable, ISupportExternalScope
    {
        private readonly IOptionsMonitor<FileLoggerOptions> _options;
        private readonly ConcurrentDictionary<string, FileLogger> _loggers;
        private IDisposable _optionsReloadToken;
        private IExternalScopeProvider _scopeProvider = NullExternalScopeProvider.Instance;

        public FileLoggerProvider(IOptionsMonitor<FileLoggerOptions> options)
        {
            this._options = options;
            this._loggers = new ConcurrentDictionary<string, FileLogger>();
            this.ReloadLoggerOptions(options.CurrentValue);
            this._optionsReloadToken = OptionsMonitorExtensions.OnChange<FileLoggerOptions>(this._options, new Action<FileLoggerOptions>(this.ReloadLoggerOptions));

        }
        public ILogger CreateLogger(string categoryName)
        {
            return this._loggers.GetOrAdd(categoryName, delegate (string loggerName)
            {
                return new FileLogger(categoryName)
                {
                    Options = this._options.CurrentValue,
                    ScopeProvider = this._scopeProvider
                };
            });
        }

        public void Dispose()
        {
            if (this._optionsReloadToken != null)
            {
                this._optionsReloadToken.Dispose();
            }
        }

        private void ReloadLoggerOptions(FileLoggerOptions options)
        {
            foreach (KeyValuePair<string, FileLogger> pair in this._loggers)
            {
                pair.Value.Options = options;
            }
        }

        public void SetScopeProvider(IExternalScopeProvider scopeProvider)
        {
            this._scopeProvider = scopeProvider;
            foreach (KeyValuePair<string, FileLogger> pair in this._loggers)
            {
                pair.Value.ScopeProvider = this._scopeProvider;
            }
        }
    }
}
